package moodish.dummy;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import moodish.comm.ClientSideMessage.Type;
import moodish.comm.ServerComm;

/**
 * 
 * Communication class for a Moodish server. The Moodish server must communicate with clients through this class.
 * This Class implements the interface {@link #ServerComm}.

 * @author Group27
 * @version 1
 */

public class ServerCommDummy implements ServerComm {
	
	public static final int PORT = 8080;
	private LinkedList<DealWithClientMessages> clients = new LinkedList<DealWithClientMessages>();
	private BlockingQueue<ServerSidesMessage> messages = new LinkedBlockingQueue<ServerSidesMessage>();

	/**
	 * Starts the Moodish server. 
	 * The method creates a server socket and begin to accept connections. After setup connections, deals with each connection separately.
	 *
	 */
	@Override
	public void start() {
		
		ServerSocket socket= null;
		
		try {
			socket = new ServerSocket(PORT);
			
			while(true){
				Socket clientsocket = socket.accept();
				DealWithClientMessages client = new DealWithClientMessages(clientsocket,this);
				clients.add(client);
				client.start();

				
			}			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

	/** 
	 * Checks if a message from a client is pending.
	 * 
	 * @return <b>true</b> if a message from a client is currently pending, otherwise <b>false</b>.
	 */
	
	@Override
	public synchronized boolean hasNextMessage() {
		return !messages.isEmpty();
	}

	/**
	 * Get the next message received from one of the clients. If no message 
	 * is has been received, the method blocks until a message has 
	 * been received. 
	 * 
	 * @return The next message sent by one of the connected clients to the server
	 */
	
	@Override
	public synchronized ServerSidesMessage getNextMessage() {
		ServerSidesMessage message = messages.element();
		messages.remove();
		return message;
	}
	
	/**
	 * Inform a client that another client is now a friend.
	 * @param toNickname  nickname of the client who has a new friend
	 * @param newFriendship nickname of the new friend
	 */
	
	@Override
	public void sendNewFriendship(String toNickname, String newFriendship) {
		 findDealWithCliente(toNickname).sendNewFriendship(newFriendship);
		
	}
	
	/**
	 * Report an error to a client.
	 * 
	 * @param toNickname nickname of the client.
	 * @param error description of the error.
	 */

	@Override
	public void sendError(String toNickname, String error) {
		 findDealWithCliente(toNickname).sendError(error);
	}


	/**
	 * Checks if a client with a certain nickname is currently connected.
	 * 
	 * @param nickname nickname of the client to check.
	 * @return <b>true</b> if a client with the nickname is currently connected, otherwise <b>false</b>.
	 */
	
	@Override
	public boolean clientIsConnected(String nickname) {
		if ( findDealWithCliente(nickname) != null)
			return  findDealWithCliente(nickname).isConnected();
		
		return false;
	}
	
	/**
	 * Inform a client that a new client has connected.
	 * 
	 * @param toNickname nickname of the client to whom to send the message.
	 * @param userConnected nickname of the connected client.
	 */

	@Override
	public void sendClientConnected(String toNickname, String userConnected) {
		 findDealWithCliente(toNickname).sendClientConnected(userConnected);
		
	}

	/**
	 * Inform a client that another client disconnected. 
	 * 
	 * @param toNickname nickname of the client to whom to send the message.
	 * @param userDisconnected nickname of client who disconnected.
	 */
	
	@Override
	public void sendClientDisconnected(String toNickname, String userDisconnected) {
		 findDealWithCliente(toNickname).sendClientDisconnected(userDisconnected);
		
	}

	/**
	 * Disconnect a client.
	 * 
	 * @param nickname nickname of the client to disconnect.
	 */
	
	@Override
	public void disconnectClient(String nickname) {
		 findDealWithCliente(nickname).disconect();
		clients.remove( findDealWithCliente(nickname));
	}

	/**
	    * Send a Moodish message to a client. 
	    * 
	    * @param fromNickname The nickname of the client from which the message was sent
	    * @param toNickname   The nickname of a friend
	    * @param moodishMessage      The message 
	    */
	
	@Override
	public void sendMoodishMessage(String fromNicename, String toNickname,
			String message) {
		 findDealWithCliente(toNickname).sendMoodishMessage(fromNicename, message);
		
	}

	/**
	 * Inform a client that a former friend has decided to not be friend anymore.
	 * 
	 * @param toNickname  nickname of the client who has lost a friend
	 * @param unfriendship nickname of the unfriendship
	 */
	
	@Override
	public void sendNewUnfriendship(String toNickname, String newFriendship) {
		 findDealWithCliente(toNickname).sendNewUnfriendship(newFriendship);
		
	}
	
	/**
	 * Find and returns a client.
	 * 
	 * @param nickname nickname of the client to find.
	 * 
	 * @return <b>client</b> if exists, otherwise <b>null</b>.
	 */
	
	public DealWithClientMessages findDealWithCliente(String nickname){
		for(DealWithClientMessages client: clients){
			if(client.getNickname().equals(nickname))
				return client;
		} return null;
			
	}
	
	/**
	 * Adds a message to a list.
	 * 
	 * @param message message to add.
	 * 
	 */

	public synchronized void addMessage(ServerSidesMessage message) {
		messages.add(message);
		
	}
	
	
}
